<?php

namespace pay;

use think\Facade;

/**
 * 支付签名工具类
 */
class EncryptHelp
{
    /**
     * 读取公钥证书
     * @param $data
     * @return string
     */
    static function loadX509Cert($path)
    {
        try {
            $file = file_get_contents($path);
            if (!$file) {
                throw new \Exception('loadx509Cert::file_get_contents ERROR');
            }
            $cert = chunk_split(base64_encode($file), 64, "\n");
            $cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n"; 
            $res = openssl_pkey_get_public($cert);
            $detail = openssl_pkey_get_details($res);

            if (!$detail) {
                throw new \Exception('loadX509Cert::openssl_pkey_get_details ERROR');
            }

            return $detail['key'];
        } catch (\Exception $e) {
            throw $e;
        }
    }


    /**
     * 读取私钥证书
     * @param [type] $path
     * @param [type] $pwd
     * @return void
     */
    static function loadPk12Cert($path, $pwd)
    {
        try {
            $file = file_get_contents($path);
            if (!$file) {
                throw new \Exception('loadPk12Cert::file
                        _get_contents');
            }

            if (!openssl_pkcs12_read($file, $cert, $pwd)) {
                throw new \Exception('loadPk12Cert::openssl_pkcs12_read ERROR');
            }
            return $cert['pkey'];
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * 生成AESKey
     * @param [type] $size
     * @return void
     */
    static function aes_generate($size)
    {
        $str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        $arr = array();
        for ($i = 0; $i < $size; $i++) {
            $arr[] = $str[mt_rand(0, 61)];
        }

        return implode('', $arr);
    }

    /**
     * AES加密
     * @param [type] $plainText
     * @param [type] $key
     * @return void
     */
    static function AESEncrypt($plainText, $key)
    {
        ksort($plainText);
        $plainText = json_encode($plainText);
        $ivlen = openssl_cipher_iv_length($cipher="AES-128-ECB");
        $iv = !$ivlen?"": openssl_random_pseudo_bytes($ivlen);
        //$iv = openssl_random_pseudo_bytes($ivlen);
        $result = openssl_encrypt($plainText, 'AES-128-ECB', $key,OPENSSL_RAW_DATA,$iv);
        //var_dump($iv);
        if (!$result) {
            throw new \Exception('报文加密错误');
        }

        return base64_encode($result);
    }

    /**
     * 公钥加密AESKey
     * @param [type] $plainText
     * @param [type] $puk
     * @return void
     */
    static function RSAEncryptByPub($plainText, $puk)
    {
        if (!openssl_public_encrypt($plainText, $cipherText, $puk, OPENSSL_PKCS1_PADDING)) {
            throw new \Exception('AESKey 加密错误');
        }

        return base64_encode($cipherText);
    }

    /**
     * 私钥签名
     * @param [type] $plainText
     * @param [type] $path
     * @return void
     */
    static function sign($plainText, $path)
    {
        //$plainText = json_encode($plainText);
        try {
            $resource = openssl_pkey_get_private($path);
            $result = openssl_sign($plainText, $sign, $resource);

            if (!$result) {
                throw new \Exception('签名出错' . $plainText);
            }

            return base64_encode($sign);
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * 请求方法
     * @param [type] $url
     * @param [type] $param
     * @return void
     */
    static function http_post_json($url, $param)
    {
        if (empty($url) || empty($param)) {
            return false;
        }
        $param = json_encode($param);
        try {
            $ch = curl_init();//初始化curl
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            //正式环境时解开注释
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $data = curl_exec($ch);//运行curl
            curl_close($ch);

            if (!$data) {
                throw new \Exception('请求出错');
            }
            return $data;
        } catch (\Exception $e) {
            throw $e;
        }

    }

    /**
     *  公钥验签
     * @param [type] $plainText
     * @param [type] $sign
     * @param [type] $path
     * @return void
     */
    static function verify($plainText, $sign, $path)
    {
        $resource = openssl_pkey_get_public($path);
        $result = openssl_verify($plainText, base64_decode($sign), $resource);

        if (!$result) {
            throw new \Exception('签名验证未通过,plainText:' . $plainText . '。sign:' . $sign, '02002');
        }

        return $result;
    }

    /**
     *  私钥解密AESKey
     * @param [type] $cipherText
     * @param [type] $prk
     * @return void
     */
    static function RSADecryptByPri($cipherText, $prk)
    {
        if (!openssl_private_decrypt(base64_decode($cipherText), $plainText, $prk, OPENSSL_PKCS1_PADDING)) {
            throw new \Exception('AESKey 解密错误');
        }

        return (string)$plainText;
    }

    /**
     *  AES解密
     * @param [type] $cipherText
     * @param [type] $key
     * @return void
     */
    static function AESDecrypt($cipherText, $key)
    {
        $result = openssl_decrypt(base64_decode($cipherText), 'AES-128-ECB', $key, 1);

        if (!$result) {
            throw new \Exception('报文解密错误', 2003);
        }

        return $result;
    }
    /**
     * 验证参数是否为空
     * @param [type] $value
     * @return void
     */
    static function checkEmpty($value)
    {
        if (!isset($value))
            return true;
        if ($value === null)
            return true;
        if (trim($value) === "")
            return true;

        return false;
    }

    /**
     * 生成参数
     * @param [type] $params
     * @return void
     */
    static function getSignContent($params) 
    {
        ksort($params);
    
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === EncryptHelp::checkEmpty($v) && "@" != substr($v, 0, 1)) {
    
                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }
    
        unset ($k, $v);
        return $stringToBeSigned;
    }

    /**
     * 受单侧回调验证
     * @param [type] $plainText     验证字符串
     * @param [type] $sign          签名数据
     * @return void
     */
    static function notify_verify($plainText, $sign)
    {
        $key_path = root_path()."public/payfile/shande/sand.cer";
        $file = file_get_contents($key_path);
        if (!$file) {
            throw new \Exception('getPublicKey::file_get_contents ERROR');
        }
        $cert   = chunk_split(base64_encode($file), 64, "\n");
        $cert   = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";
        $res    = openssl_pkey_get_public($cert);
        $detail = openssl_pkey_get_details($res);
        if (!$detail) {
            throw new \Exception('getPublicKey::openssl_pkey_get_details ERROR');
        }
        $resource = openssl_pkey_get_public($detail['key']);
        $result = openssl_verify($plainText, base64_decode($sign), $resource);
        return $result;
    }

}